package com.netx.ebs;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import com.netx.data.Connection;
import com.netx.data.DatabaseException;
import com.netx.data.NoSuchInstanceException;
import com.netx.data.ValueList;
import com.netx.generics.basic.Checker;
import com.netx.generics.collections.ImmutableSet;
import com.netx.generics.sql.Row;
import com.netx.generics.sql.Table;


public class Roles extends EbsEntity {

	public Roles() {
	}

	public long add(String name, String description, String loginResource, Permission[] permissions) throws DatabaseException {
		Checker.checkNullElements(permissions, "permissions");
		ValueList values = new ValueList();
		values.addValue("name", name);
		values.addValue("description", description);
		values.addValue("login_resource", loginResource);

		Connection c = getConnection();
		synchronized(c) {
			startTransaction();
			long roleID = insert(values);
			for(int i=0; i<permissions.length; i++) {
				insertRelation(roleID, permissions[i].getPrimaryKey());
			}
			commit();
			return roleID;
		}
	}

	public void change(long roleID, String name, String description, String loginResource) throws DatabaseException {
		ValueList values = new ValueList();
		values.addValue("name", name);
		values.addValue("description", description);
		values.addValue("login_resource", loginResource);
		if(update(roleID, values) == 0) {
			throw new NoSuchInstanceException("roleID: "+roleID);
		}
		// Update running sessions:
		Iterator<Session> it = sManager.getAllSessions().iterator();
		while(it.hasNext()) {
			Session s = (Session)it.next();
			if(s.getUser().getRole().getPrimaryKey() == roleID) {
				s.getUser().getRole().update(name, description, loginResource);
			}
		}
	}
	
	public void change(long roleID, Permission[] permissions) throws DatabaseException {
		Checker.checkNullElements(permissions, "permissions");
		if(!exists(roleID)) {
			throw new NoSuchInstanceException("roleID: "+roleID);
		}
		else {
			synchronized(getConnection()) {
				startTransaction();
				for(int i=0; i<permissions.length; i++) {
					insertRelation(roleID, permissions[i].getPrimaryKey());
				}
				commit();
			}
			// update running sessions
			Iterator<Session> it = sManager.getAllSessions().iterator();
			while(it.hasNext()) {
				Session s = (Session)it.next();
				if(s.getUser().getRole().getPrimaryKey() == roleID) {
					s.getUser().getRole().setPermissions(permissions);
				}
			}
		}
	}

	public void remove(long roleID) throws DatabaseException {
		if(delete(roleID) == 0) {
			throw new NoSuchInstanceException("roleID: "+roleID);
		}
	}
	
	public Role find(long roleID) throws DatabaseException {
		Row data = select("role_id, name, description, login_resource", roleID);
		if(data == null) {
			return null;
		}
		else {
			return new Role(data, findPermissions(roleID));
		}
	}
	
	public Role find(String name) throws DatabaseException {
		Checker.checkEmpty(name, "name");
		Table result = getConnection().select("role_id, name, description, login_resource FROM roles WHERE name=\""+name+"\"");
		if(result.isEmpty()) {
			return null;
		}
		else {
			return new Role(result.getRow(0), findPermissions(result.getLong(1, 0)));
		}
	}
	
	public ImmutableSet<Role> getAll() throws DatabaseException {
		Table roles = getConnection().select("role_id, name, description, login_resource FROM roles");
		Set<Role> all = new HashSet<Role>();
		for(int i=0; i<roles.getRowCount(); i++) {
			all.add(new Role(roles.getRow(i), findPermissions(roles.getRow(i).getLong(1))));
		}
		return new ImmutableSet<Role>(all);
	}

	// for Users.find and self
	Permission[] findPermissions(long roleID) throws DatabaseException {
		Table t = getConnection().select("permissions.permission_id, permissions.name FROM permissions, role_permissions, roles WHERE permissions.permission_id=role_permissions.permission_id AND role_permissions.role_id=roles.role_id AND roles.role_id="+roleID);
		Permission[] permissions = new Permission[t.getRowCount()];
		for(int i=0; i<t.getRowCount(); i++) {
			permissions[i] = new Permission(t.getRow(i));
		}
		return permissions;
	}
}
